home *** CD-ROM | disk | FTP | other *** search
- /*
- * A version of Ward Christensen's file transfer protocol for
- * Unix System V or 4.2 bsd.
- *
- * Emmet P. Gray, ..!ihnp4!uiucuxc!fthood!egray, 16 Aug 85
- *
- * Modified by Sanford Zelkovitz 08/18/86
- * Last modification date = 05/20/87
- * Modified for KA9Q NOS BBS - WA3DSP 2/93
- */
-
-
- #include <stdio.h>
- #include <io.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <stdarg.h>
- #include "dirutil.h"
- #include "timer.h"
- #include "socket.h"
- #include "mailbox.h"
-
- #ifdef XMODEM
-
- #ifdef min
- #undef min
- #endif
-
- #define SPEED 2400 /* Serial line Baudrate */
-
- #define MAXERRORS 10 /* max number of times to retry */
- #define SECSIZE 128 /* CP/M sector, transmission block */
- #define CPMEOF 26 /* End Of File (for CP/M) */
- #define SOH 1 /* Start Of Header */
- #define STX 2 /* Start of 1K block */
- #define EOT 4 /* End Of Transmission */
- #define ACK 6 /* ACKnowledge */
- #define NAK 21 /* Negative AcKnowledge */
- #define CAN 24 /* CANcel */
- #define BS 8 /* Backspace */
-
- static int recvfile __ARGS((char*,struct mbx *m));
- static int sendfile __ARGS((char*,struct mbx *m));
- static int truncate __ARGS((struct mbx *m,char *path,long length));
- static char getchar_t __ARGS((int socket));
- static void update_crc __ARGS((unsigned char c, unsigned char *crc1, unsigned char *crc2));
- static void error __ARGS((struct mbx *m));
- static void print_text __ARGS((struct mbx *m,char *fmt, ...));
- static void rawmode __ARGS((struct mbx *));
- static void restoremode __ARGS((struct mbx *));
-
- doxmodem(mode, filename, p)
- char mode, *filename;
- void *p;
- {
- int exit_return=0, oldflush;
- struct mbx *m;
-
- m = (struct mbx *)p;
- oldflush=setflush(m->user,-1);
-
- switch (mode) {
- case 'r':
- case 'R':
- exit_return=recvfile(filename,m);
- break;
- case 's':
- case 'S':
- exit_return=sendfile(filename,m);
- break;
- default :
- print_text(m,"Xmodem: Invalid Option\n");
- }
- restoremode(m);
- usputc(m->user,'\n');
- usflush(m->user);
- setflush(m->user,oldflush);
- return(exit_return);
- }
-
- /* send a file to the remote */
- static int
- sendfile(tfile, m)
- char *tfile;
- struct mbx *m;
- {
- FILE *fp;
- unsigned char chr, checksum, block, sector[SECSIZE];
- unsigned char crc1, crc2, mode, errcount, errcount2, two_can;
- int i, nbytes, speed=SPEED;
- long size, min, sec;
-
- if ((size=fsize(tfile))==-1){
- print_text(m,"xmodem: Can't open '%s' for read\n", tfile);
- return(1);
- }
-
- if (!(fp = fopen(tfile, READ_BINARY))) {
- print_text(m,"xmodem: Can't open '%s' for read\n", tfile);
- return(1);
- }
-
- size=(size/128L)+1L;
- sec = size * 128L * 15L / speed;
- min = sec / 60L;
- sec = sec - min * 60L;
- print_text(m,"\nFile open: %d records\n", size);
- print_text(m,"Send time: %ld min, %ld sec at %d baud\n", min, sec, speed);
- print_text(m,"To cancel: use CTRL-X numerous times\n");
- print_text(m,"Waiting receive ready signal\n");
-
- mspause(3000L);
- rawmode(m);
- errcount = 0;
- mode = 0;
- two_can=0;
- block = 1;
-
- while (errcount < MAXERRORS) {
- chr = getchar_t(m->user);
- if (chr == NAK) /* checksum mode */
- break;
- if (chr == 'C') { /* CRC mode */
- mode = 1;
- break;
- }
- if (chr == CAN) {
- if (two_can) {
- mspause(3000L);
- print_text(m,"\nxmodem: Abort request received\n");
- fclose(fp);
- return(1);
- }
- two_can=1;
- } else {
- two_can=0;
- }
-
- errcount++;
- }
- if (errcount >= MAXERRORS) {
- mspause(3000L);
- print_text(m,"xmodem: Timed out on acknowledge\n");
- fclose(fp);
- return(1);
- }
- two_can=0;
- while ((nbytes= fread(sector,1,128, fp))!=0) {
- if (nbytes < SECSIZE) { /* fill short sector */
- for (i=nbytes; i < SECSIZE; i++)
- sector[i] = CPMEOF;
- }
- errcount = 0;
- while (errcount < MAXERRORS) {
- usputc(m->user,SOH); /* the header */
- usputc(m->user,block); /* the block number */
- chr = ~block;
- usputc(m->user,chr); /* it's complement */
- checksum = 0;
- crc1 = 0;
- crc2 = 0;
- for (i=0; i < SECSIZE; i++) {
- usputc(m->user,sector[i]);
- if (mode)
- update_crc(sector[i],&crc1,&crc2);
- else
- checksum += sector[i];
- }
- if (mode) {
- update_crc(0,&crc1,&crc2);
- update_crc(0,&crc1,&crc2);
- usputc(m->user,crc1);
- usputc(m->user,crc2);
-
- }
- else
- usputc(m->user,checksum);
-
- usflush(m->user);
- errcount2=0;
- rec_loop:
-
- chr = getchar_t(m->user);
- if (chr == CAN) {
- if (two_can) {
- mspause(3000L);
- print_text(m,"\nxmodem: Abort request received\n");
- fclose(fp);
- return(1);
- }
- two_can=1;
- } else {
- two_can=0;
- }
-
- if (chr == ACK)
- break; /* got it! */
- /* noise on line? */
- if (chr != NAK ) {
- ++errcount2;
- if (errcount2>=MAXERRORS) {
- error(m);
- fclose(fp);
- return 1;
- }
- goto rec_loop;
- }
- errcount++;
- }
- if (errcount >= MAXERRORS) {
- error(m);
- fclose(fp);
- return(1);
- }
- block++;
- }
- errcount = 0;
- while (errcount < MAXERRORS) {
- usputc(m->user,EOT);
- usflush(m->user);
- if (getchar_t(m->user) == ACK)
- {
- fclose(fp);
- mspause(6000L);
- log(m->user,"Xmodem: Download - %s",tfile);
- print_text(m,"Xmodem: File sent OK\n");
- return(0);
- }
- errcount++;
- }
- fclose(fp);
- mspause(3000L);
- error(m);
- return(1);
- }
-
- /* receive a file from the remote */
- static int
- recvfile(tfile, m)
- char *tfile;
- struct mbx *m;
- {
- FILE *fp;
- unsigned char hdr, blk, cblk, tmp, cksum, crc1, crc2;
- unsigned char c1, c2, sum, block, sector[SECSIZE];
- unsigned char first, mode, errcount, two_can;
- int i;
-
- if (!access(tfile, 00)) {
- print_text(m,"xmodem: File %s already exists\n",tfile);
- return(1);
- }
-
- if (!(fp = fopen(tfile, WRITE_BINARY))) {
- print_text(m,"xmodem: Can't open '%s' for write\n", tfile);
- return(1);
- }
- print_text(m,"File open - ready to receive\n");
- print_text(m,"To cancel: use CTRL-X numerous times\n");
- mspause(3000L);
- rawmode(m);
- errcount = 0;
- block = 1;
- first=0;
- two_can=0;
-
- mspause(3000L);
- while (errcount < MAXERRORS) {
- if (errcount < (MAXERRORS / 2)) {
- usputc(m->user,'C'); /* try CRC mode first */
- usflush(m->user);
- mode = 1;
- }
- else {
- usputc(m->user,NAK); /* then checksum */
- usflush(m->user);
- mode = 0;
- }
- if ((hdr = getchar_t(m->user)) == SOH) {
- first=1;
- break;
- }
- if (hdr == CAN) {
- if (two_can){
- mspause(3000L);
- print_text(m,"\nxmodem: Abort request received\n");
- fclose(fp);
- unlink(tfile);
- return(1);
- }
- two_can=1;
- } else {
- two_can=0;
- }
- errcount++;
- }
- if (errcount >= MAXERRORS) {
- mspause(3000L);
- print_text(m,"\nxmodem: Timed out on acknowledge\n");
- fclose(fp);
- unlink(tfile);
- return(1);
- }
- errcount = 0;
- two_can=0;
- while (errcount < MAXERRORS) {
-
- if (first) {
- hdr=SOH;
- first=0;
- } else
- hdr = getchar_t(m->user);
-
- if (hdr == CAN) {
- if (two_can){
- mspause(3000L);
- print_text(m,"\nxmodem: Abort request received\n");
- fclose(fp);
- unlink(tfile);
- return(1);
- }
- two_can=1;
- continue;
- } else {
- two_can=0;
- }
-
- if (hdr == EOT) /* done! */
- break;
-
- if (hdr != SOH) { /* read in junk for 6 seconds */
- alarm(6000L);
- while(errno != EALARM)
- rrecvchar(m->user);
- alarm(0L); /* cancel alarm */
- first=0;
- goto nak;
- }
- blk = getchar_t(m->user);
- cblk = getchar_t(m->user);
- crc1 = 0;
- crc2 = 0;
- sum = 0;
- for (i=0; i < SECSIZE; i++) {
- sector[i] = getchar_t(m->user);
- if (mode)
- update_crc(sector[i],&crc1,&crc2);
- else
- sum += sector[i];
- }
- if (mode) {
- c1 = getchar_t(m->user);
- c2 = getchar_t(m->user);
- }
- else
- cksum = getchar_t(m->user);
- if (blk != block && blk != (block - 1))
- goto nak;
- tmp = ~blk;
- if (cblk != tmp)
- goto nak;
- if (mode) {
- update_crc(0,&crc1,&crc2);
- update_crc(0,&crc1,&crc2);
- if (c1 != crc1 || c2 != crc2)
- goto nak;
- }
- else {
- if (cksum != sum)
- goto nak;
- }
- if (block == blk) {
- fflush(fp);
- if (fwrite(sector, sizeof(sector[0]), SECSIZE, fp)!=SECSIZE){
- error(m);
- print_text(m," File write error - Partial file deleted\n");
- fclose(fp);
- unlink(tfile);
- return (1);
- }
- }
- block = blk + 1;
- usputc(m->user,ACK); /* got it! */
- usflush(m->user);
- errcount = 0;
- continue;
-
- nak: usputc(m->user,NAK); /* do it over */
- usflush(m->user);
- errcount++;
- }
- if (errcount == MAXERRORS) {
- error(m);
- fclose(fp);
- unlink(tfile);
- return(1);
- }
- usputc(m->user,ACK);
- usflush(m->user);
- mspause(3000L);
- fclose(fp);
- log(m->user,"Xmodem: Upload - %s",tfile);
- print_text(m,"Xmodem: File received OK\n");
- return(0);
- }
-
- /* exceeded the maximum number of retry's */
- static void
- error(m)
- struct mbx *m;
- {
- int i;
-
- for(i=0;i<9;i++) {
- usputc(m->user,CAN);
- }
- usflush(m->user);
- mspause(1000L);
- for(i=0;i<9;i++) {
- usputc(m->user,BS);
- }
- usflush(m->user);
- mspause(3000L);
- print_text(m,"\nxmodem: Exceeded error limit...aborting\n");
- return;
- }
-
- /* update the CRC bytes */
- static void
- update_crc(c, crc1, crc2)
- unsigned char c, *crc1, *crc2;
- {
- register int i, temp;
- register unsigned char carry, c_crc1, c_crc2;
-
- for (i=0; i < 8; i++) {
- temp = c * 2;
- c = temp; /* rotate left */
- carry = ((temp > 255) ? 1 : 0);
- temp = *crc2 * 2;
- *crc2 = temp;
- *crc2 |= carry; /* rotate with carry */
- c_crc2 = ((temp > 255) ? 1 : 0);
- temp = *crc1 * 2;
- *crc1 = temp;
- *crc1 |= c_crc2;
- c_crc1 = ((temp > 255) ? 1 : 0);
- if (c_crc1) {
- *crc2 ^= 0x21;
- *crc1 ^= 0x10;
- }
- }
- return;
- }
-
- /* getchar with a 5 sec time out */
- static char
- getchar_t(s)
- int s;
- {
- char c;
- /* only have 5 sec... */
- alarm(5000L);
- /* Wait for something to happen */
- c=rrecvchar(s);
- alarm(0L);
- return(c);
- }
-
- /* put the stdin/stdout in the "raw" mode */
- static void
- rawmode(m)
- struct mbx *m;
- {
- seteol(m->user,0);
- seteol(m->tip->s,0);
- sockmode(m->tip->s,SOCK_BINARY);
- sockmode(m->user,SOCK_BINARY);
- m->tip->raw=1;
- }
-
- static void
- restoremode(m)
- struct mbx *m;
- {
- while(socklen(m->user,0) != 0)
- recv_mbuf(m->user,NULL,0,NULLCHAR,0);
- seteol(m->user,"\n");
- seteol(m->tip->s,"\n");
- sockmode(m->user,SOCK_ASCII);
- sockmode(m->tip->s,SOCK_ASCII);
- m->tip->raw=0;
- }
-
- void
- #ifdef TNOS_68K
- print_text(m, fmt)
- struct mbx *m;
- char *fmt;
- #else
- print_text (struct mbx *m,char *fmt, ...)
- #endif
- {
- va_list ap;
- char buf[80];
-
- restoremode(m);
- va_start(ap,fmt);
- vsprintf(buf,fmt,ap);
- va_end(ap);
- usprintf(m->user,buf);
- usflush(m->user);
- }
-
- #endif
-